class_name ConditionUtil

## condition_func 检测方法
static var condition_dict:Dictionary = {
	#GameEnum.Condition.Temp : {
		#condition_func = check_none_condition,
	#},
	None = {
		none_func = check_none_condition,
	},
	CanAttack = {
		condition_func = check_can_attack_condition,
	},
	CurHealthGreaterEqual = {
		condition_func = check_cur_health_condition,
		is_greate_equal = true,
		value = 100, # 如果是比例，此处填一个float值，例如0.5
	},
	CurHealthLessEqual = {
		condition_func = check_cur_health_condition,
		is_greate_equal = false,
		value = 100,
	},
	#region Skeleton
	Skeleton_CheckReact = {
		condition_func = check_target_count_greater_equal_condition,
		count = 1,
		radius = 100,
		is_visible = true,
	},
	Skeleton_CanAttack = {
		condition_func = check_target_in_area_condition,
		area2D_idxs = [
			0,
		],
		is_visible = true,
		is_all = false,
		min_count = 1,
	},
	#endregion
}

#region Func

## 检测方法模板
static func check_temp_condition(condition_info,args:Dictionary = {}) -> bool:
	var entity = args.entity
	return false
## 空检测 直接返回true
static func check_none_condition(condition_info,args:Dictionary = {}) -> bool:
	return true
## 检测能否攻击
static func check_can_attack_condition(condition_info,args:Dictionary = {}) -> bool:
	var entity = args.entity
	var component = entity.get_component_by_name("WeaponC_StateManager") as WeaponC_StateManager
	if (component.fsm.expression_properties.attack == GameEnum.KeyActionState.Pressed or component.fsm.expression_properties.attack == GameEnum.KeyActionState.Stay) and component.fsm.expression_properties.cur_count > 0:
		return true
	return false
## 检测当前生命值
## is_greater_equal:是否是>=
## value:对比值，如果为浮点数，value = max_health * value
static func check_cur_health_condition(condition_info,args:Dictionary = {}) -> bool:
	var entity = args.entity
	var is_greater_equal = condition_info.is_greate_equal
	var value = condition_info.value
	var component = entity.get_component_by_name("HealthComponent") as HealthComponent
	var cur_health = component.cur_health
	# 比例计算
	if typeof(value) == TYPE_FLOAT:
		var data = entity.get_entity_data()
		var max_health = data.max_health
		return float(cur_health) >= float(max_health) * value if is_greater_equal else float(cur_health) <= float(max_health) * value
	# 数值计算
	else:
		return cur_health >= value if is_greater_equal else cur_health <= value
	return false
## 检测当前目标数量
## count:数量
## radius:检测半径 -1无限制
## is_visible:目标是否可见
## is_inversion:数量判断条件反转
## area2D_ids:area2D idx索引列表，不为空会启用区域检测
## is_all:上方的区域检测是否需要全部满足
static func check_target_count_greater_equal_condition(condition_info,args:Dictionary = {}) -> bool:
	var entity = args.entity
	var count:int = Util.get_value_or_default(condition_info,"count",0)
	var radius:float = Util.get_value_or_default(condition_info,"radius",-1)
	var is_visible:bool = Util.get_value_or_default(condition_info,"is_visible",false)
	var is_inversion:bool = Util.get_value_or_default(condition_info,"is_inversion",false)
	var area2D_idxs:Array = Util.get_value_or_default(condition_info,"area2D_idxs",[])
	var is_all = Util.get_value_or_default(condition_info,"is_all",false)
	
	var detect_component = entity.get_component_by_name("DetectComponent") as DetectComponent
	var target_detector:TargetDetector = detect_component.get_detector(GameEnum.DetectorType.Target) as TargetDetector
	var targets:Array = []
	if is_visible:
		targets = target_detector.visible_entities
	else:
		targets = target_detector.entities
	if radius >= 0:
		targets = targets.filter(func (x):
			return (x.global_position - target_detector.global_position).length() <= radius
		)
	targets = targets.filter(func (x):
		var amount = 0
		for id in area2D_idxs:
			var area2d = detect_component.get_area2d(id)
			if area2d:
				amount += 1 if area2d.overlaps_body(x.logic_body_area) else 0
		return amount == area2D_idxs.size() if is_all else (amount > 0 or area2D_idxs.size() == 0)
	)
	return targets.size() < count if is_inversion else targets.size() >= count
## 检测区域内目标
## area2D_idxs:area2D idx索引列表，不为空会启用区域检测
## is_visible:目标是否可见
## is_all:上方的区域检测是否需要全部满足
## min_count:最小数量
static func check_target_in_area_condition(condition_info,args:Dictionary = {}) -> bool:
	var entity = args.entity
	var area2D_idxs = Util.get_value_or_default(condition_info,"area2D_idxs",[])
	var is_visible:bool = Util.get_value_or_default(condition_info,"is_visible",false)
	var is_all = Util.get_value_or_default(condition_info,"is_all",false)
	var min_count = Util.get_value_or_default(condition_info,"min_count",1)
	var component:Area2DDetectComponent = entity.get_component_by_name("Area2DDetectComponent") as Area2DDetectComponent
	var detect_component = entity.get_component_by_name("DetectComponent") as DetectComponent
	var target_detector:TargetDetector = detect_component.get_detector(GameEnum.DetectorType.Target) as TargetDetector
	var targets:Array = []
	if is_visible:
		targets = target_detector.visible_entities
	else:
		targets = target_detector.entities
	targets = targets.filter(func (t):
		var amount = 0
		for id in area2D_idxs:
			var area2d = component.get_area2d(id)
			if area2d:
				amount += 1 if area2d.overlaps_area(t.logic_body_area) else 0
		return amount == area2D_idxs.size() if is_all else (amount > 0 or area2D_idxs.size() == 0)
		)
	return targets.size() >= min_count
static func check_fsm_expression_prop_condition(condition_info,args:Dictionary = {}) -> bool:
	var fsm = args.fsm as FSM
	var res = true
	for key in condition_info.check_kv:
		if not fsm.expression_properties.has(key):
			res = res and false
			break
		if fsm.expression_properties[key] != condition_info.check_kv[key]:
			res = res and false
			break
	return res
#endregion

static func check_condition(condition,args:Dictionary = {}):
	if typeof(condition) == TYPE_ARRAY:
		return _check_array_condition(condition,args)
	else:
		return _check_single_condition(condition,args)
		
static func _check_single_condition(condition,args:Dictionary = {}) -> bool:
	if not condition_dict.has(condition):
		return false
	var condition_info = condition_dict[condition]
	if not ("condition_func" in condition_info):
		return true
	return condition_info.condition_func.call(condition_info,args)

static func _check_array_condition(condition,args:Dictionary = {}) -> bool:
	var res:bool = true
	for con in condition:
		res = res and _check_single_condition(con,args)
	return res

